#include "logout.hh"
#include "protocol.hh"
#include <iostream>
#include <memory>
#include <string>
#include <strings.h>
#include <cstring>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
using namespace std;

#define buffer_size 1024

class tcp_server_t
{
public:
    tcp_server_t(string addr, uint16_t port)
    {
        // tcp
        _listen_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listen_socket_fd < 0)
        {
            log_error("creat_listen_socket_error!", SOCKET_CREAT_ERROR);
        }
        // info
        sockaddr_in host_addr;
        bzero(&host_addr, sizeof(host_addr));
        host_addr.sin_addr.s_addr = (addr.empty() ? INADDR_ANY : inet_addr(addr.c_str()));
        host_addr.sin_family = AF_INET;
        host_addr.sin_port = htons(port);
        // bind
        if (bind(_listen_socket_fd, (const sockaddr *)&host_addr, sizeof(host_addr)) < 0)
        {
            log_error("bind_error!", BIND_ERROR);
        }
    }
    void run()
    {
        // 监听
        if (listen(_listen_socket_fd, 5) < 0)
        {
            log_error("listen_error!", LISTEN_ERROR);
        }
        sockaddr_in client;
        socklen_t client_len = sizeof(client);

        while (true)
        {
            // 连接
            int client_fd = accept(_listen_socket_fd, (sockaddr *)&client, &client_len);
            if (client_fd < 0)
            {
                log_error("accept_error!", ACCEPT_ERROR);
            }
            // 新建执行流(子进程,或多线程)提供服务
            // 线程
            pthread_t tid = 0;
            client_thread_argc *argc = new client_thread_argc{client_fd, this};
            if (pthread_create(&tid, 0, thread_routine, argc) < 0)
            {
                log_error("thread_create_error!", THREAD_CREATE_ERROR);
            }
        }
    }

private:
    response calculate(const request &req)
    {
        int a = req._a;
        int b = req._b;
        char op = req._op;
        response ret;
        if (op == '+')
        {
            ret._exit_code = 0;
            ret._result = a + b;
        }
        else if (op == '-')
        {
            ret._exit_code = 0;
            ret._result = a - b;
        }
        else if (op == '*')
        {
            ret._exit_code = 0;
            ret._result = a * b;
        }
        else if (op == '/')
        {
            if (b == 0)
            {
                ret._exit_code = 1;
                ret._result = -1;
            }
            else
            {
                ret._exit_code = 0;
                ret._result = a / b;
            }
        }
        else if (op == '%')
        {
            if (b == 0)
            {
                ret._exit_code = 1;
                ret._result = -1;
            }
            else
            {
                ret._exit_code = 0;
                ret._result = a % b;
            }
        }
        return ret;
    }
    static void *thread_routine(void *argc_struct)
    {
        // 获取参数+线程分离
        pthread_detach(pthread_self());
        auto argc = (client_thread_argc *)argc_struct;
        // 1.接收客户端序列化报文
        // 2.提取有效载荷
        // 此时可能出现读取不完整的情况,若如此就继续读取保证读取到完整报文.
        // 3.反序列化生成请求结构化数据
        // 4.计算 获取回应结构化数据
        // 5.序列化 回应获取有效载荷
        // 6.添加包头 获取报文
        // 7.将报文发送给客户端
        volatile bool quit = false;
        string request_package = "";
        while (!quit)
        {
            // 1
            char read_buffer[buffer_size];
            bzero(read_buffer, buffer_size);
            ssize_t read_size = read(argc->_fd, read_buffer, buffer_size - 1);
            if (read_size == 0)
            {
                cout << "客户端退出..." << endl;
                quit = true;
                continue;
            }
            request_package += read_buffer;
            // 2.
            auto decode_ret = decode(request_package);
            if (decode_ret.first == false)
            {
                continue;
            }
            string payload(decode_ret.second);
            // 3.
            request req;
            req.deserialize(payload);
            // 4.
            response cal_result = argc->_this->calculate(req);
            // 5.
            string write_package = cal_result.serialize();
            // 6.
            encode(write_package);
            // 7.
            write(argc->_fd, write_package.c_str(), write_package.size());
        }
        // 切记资源泄漏
        close(argc->_fd);
        delete argc;
    }

private:
    struct client_thread_argc
    {
        client_thread_argc(int fd, tcp_server_t *pthis)
            : _fd(fd), _this(pthis) { ; }
        tcp_server_t *_this;
        int _fd;
    };
    int _listen_socket_fd;
};